from common_data import XMLRPCServerConfig, User
from xmlrpc_base_resource import XMLRPC_BaseResource
from twisted.internet import reactor, ssl
from twisted.web import server, resource
from twisted.python import log
from OpenSSL.SSL import SSLv3_METHOD
from datetime import datetime
import sys

class XMLRPC_Server( server.Site ):
    
    current_config = None
    config_last_modified = 0
    
    def __init__(self, standalone = False ):
        """ load config
        """
        log.msg( 'Server init' )
        
        self.standalone = ( standalone and True ) or False
        
        # initialize db connection
        import db_connection
    
        try:
            db_connection.connectToDb()
        except:
            log.err()
        
        # insert default config
        if not XMLRPCServerConfig.select().count():
            XMLRPCServerConfig()
            
        # insert default user
        if not User.select().count():
            User( name = 'admin', password = 'admin', admin = 1 )

        # load custom config
        self.updateLatestConfigLoop()
        
        self.root_resource = RootResource()
        
        server.Site.__init__(self, resource = self.root_resource)
        
        self.http_listener = self.assignListener() 
        
    def updateLatestConfigLoop(self):
        """ check for newer config; if present loads the config and restarts services if necessary; then registers its next iteration
        """

        try:
            newer_config = XMLRPCServerConfig.select( XMLRPCServerConfig.q.modified_time > self.config_last_modified ).count()
        except:
            log.err()
            sys.exit()
          
        if newer_config:
            log.msg( 'newer config found' )
            
            restart_listener = False
            
            try:
                new_config = list( XMLRPCServerConfig.select( orderBy=XMLRPCServerConfig.q.creation_time ).reversed() )[0]
            except:
                log.err('cannot load server config')
            
            if not self.current_config:
                self.current_config = dict()
            
            if self.current_config and \
                    ( self.current_config[ 'http_port' ] != new_config.http_port or \
                    self.current_config['enable_ssl'] != new_config.enable_ssl or \
                    self.current_config['ssl_key'] != new_config.ssl_key or \
                    self.current_config['ssl_certificate'] != new_config.ssl_certificate ):
                    restart_listener = True
                        
            self.current_config['http_port'] = new_config.http_port
            self.current_config['config_refresh_interval'] = new_config.config_refresh_interval
            self.current_config['enable_ssl'] = new_config.enable_ssl
            self.current_config['ssl_key'] = ( new_config.ssl_key and new_config.ssl_key ) or "" 
            self.current_config['ssl_certificate'] = ( new_config.ssl_certificate and new_config.ssl_certificate ) or ""
            
            if restart_listener and self.http_listener:
                if self.standalone:
                    self.http_listener.stopListening().addCallback(
                        lambda *x: setattr( self, 'http_listener', self.assignListener() ) )
                else:
                    self.http_listener.stopService().addCallback( 
                        lambda *x: setattr( self, 'http_listener', self.assignListener() ) ).addCallback( 
                        lambda *x: self.http_listener.startService() )
                                
            self.config_last_modified = datetime.now()
            
        reactor.callLater( self.current_config[ 'config_refresh_interval' ], self.updateLatestConfigLoop )
        
    def assignListener(self):
        """ creates and returns http listener
        """
        # ssl
        if self.current_config['enable_ssl']:
            if self.current_config['ssl_key'] is '' or self.current_config['ssl_certificate'] is '':
                raise Exception( 'ssl config is invalid' )
        
            log.msg( 'starting listener with ssl' )
            
            if self.standalone:
                return reactor.listenSSL( self.current_config['http_port'], self, ssl.DefaultOpenSSLContextFactory( self.current_config['ssl_key'], self.current_config['ssl_certificate'] ) )
            else:
                from twisted.application import internet
                return internet.SSLServer( self.current_config['http_port'], self, ssl.DefaultOpenSSLContextFactory( self.current_config['ssl_key'], self.current_config['ssl_certificate'] ) )
        # non-ssl
        else:
            log.msg( 'starting listener' )
            
            if self.standalone:
                return reactor.listenTCP( self.current_config['http_port'], self )
            else:
                from twisted.application import internet
                return internet.TCPServer( self.current_config['http_port'], self )
                    
class RootResource( resource.Resource ):
    def __init__(self):
        resource.Resource.__init__(self)
        
        self.putChild('RPC2', XMLRPC_BaseResource() )